<template>
  <div class="ol-map" id="olMap"></div>
</template>

<script lang='ts' setup>
import {ref, reactive, toRefs, onMounted, nextTick, watch} from 'vue'
import Map from 'ol/Map'  // OpenLayers的主要类，用于创建和管理地图
import View from 'ol/View'  // OpenLayers的视图类，定义地图的视图属性
import {Tile as TileLayer} from 'ol/layer'  // OpenLayers的瓦片图层类
import {XYZ, OSM} from 'ol/source'  // OpenLayers的瓦片数据源，包括XYZ格式和OpenStreetMap专用的数据源
import {fromLonLat, toLonLat} from 'ol/proj'  // OpenLayers的投影转换函数，用于经纬度坐标和投影坐标之间的转换
import {
  defaults as defaultInteractions,
  DragRotateAndZoom,
} from 'ol/interaction'  // OpenLayers的交互类，包括默认的交互集合和特定的旋转缩放交互
import {defaults, FullScreen, MousePosition, ScaleLine} from 'ol/control'  // OpenLayers的控件类，包括默认的控件集合和特定的全屏、鼠标位置、比例尺控件
import Feature from 'ol/Feature'  // OpenLayers的要素类，表示地图上的一个对象或实体
import Point from 'ol/geom/Point'  // OpenLayers的点几何类，用于表示点状的地理数据
import {Vector as VectorLayer} from 'ol/layer'  // OpenLayers的矢量图层类，用于显示矢量数据
import {Vector as VectorSource} from 'ol/source'  // OpenLayers的矢量数据源类，用于管理和提供矢量数据
import LineString from 'ol/geom/LineString'  // OpenLayers的线几何类，用于表示线状的地理数据
import {Circle as CircleStyle, Style, Text, Stroke, Fill, Icon} from "ol/style"  // OpenLayers的样式类，用于定义图层的样式，包括圆形样式、基本样式、边框、填充和图标
import Polygon from "ol/geom/Polygon"
import {defineProps, withDefaults} from "vue/dist/vue";  // OpenLayers的多边形几何类，用于表示面状的地理数据import { Circle as CircleStyle, Stroke, Fill, Icon } from "ol/style"  // OpenLayers的样式类，用于定义图层的样式，包括圆形样式、基本样式、边框、填充和图标

import useNode from "../store/node";
import {storeToRefs} from "pinia";
import useFiber from "../store/fiber";
import useWDM from "../store/wdm";
import useDemand from "../store/demand";

interface MapProps {
  url: string;
  viewConfig: any;
  eventConfig: any;
  nodes: any;
  links: any;
  text: any;
}

const props = withDefaults(defineProps<MapProps>(), {
  url: () => "http://localhost:18082/{z}/{x}/{y}.png",
  viewConfig: () => {
    return {
      // fromLonLat是一个函数，用于将经纬度坐标转换为地图的坐标系统。
      center: fromLonLat([108.924652, 34.208527]),//地图中心点
      zoom: 5,// 缩放级别
      projection: 'EPSG:3857',
      minZoom: 6,// 最小缩放级别
      maxZoom: 12,// 最大缩放级别
      constrainResolution: true// 因为存在非整数的缩放级别，所以设置该参数为true来让每次缩放结束后自动缩放到距离最近的一个整数级别，这个必须要设置，当缩放在非整数级别时地图会糊
    }
  },
  eventConfig:()=>{
    return{
      clickEvent:()=>{}
    }
  },
  nodes: () => {},
  links: () => {},
  text: () => {},
})

const nodeStore = useNode();
const {nodeList}=storeToRefs(nodeStore);
const fiberStore = useFiber();
const {fiberList}=storeToRefs(fiberStore);
const wdmStore = useWDM();
const {wdmList}=storeToRefs(wdmStore);
const demandStore =useDemand()
const {demandList}=storeToRefs(demandStore);

let map= null; // map地图
let fiberLayer=new VectorLayer({
  source: new VectorSource(),
}); //线图层
let pointLayer=new VectorLayer({
  source: new VectorSource(),
}); //点图层

let wdmLayer=new VectorLayer({
  source: new VectorSource(),
}); //线图层

let demandLayer=new VectorLayer({
  source: new VectorSource(),
}); //业务图层


//监听储存在pinia中的数据
watch(nodeList, (newVal, oldVal) => { // console.log(newVal)
  // console.log("newVal",newVal)
  // console.log("oldVal",oldVal)
  console.log("props.nodes",nodeList.value)
  // nodeList.value.forEach((item: any) => {
  //   //把每个点进行绘制
  //   drawPoint(item, {})
  // })
  drawPoints(nodeList.value, {})
  // console.log(map.getLayers())
}, {deep: true})


//监听储存在pinia中的数据
watch(fiberList, (newVal, oldVal) => {
  console.log("props.nodes",fiberList.value)
  drawLines(fiberList.value,fiberLayer, {})
}, {deep: true})

//监听储存在pinia中的数据
watch(wdmList, (newVal, oldVal) => {
  console.log("props.nodes",wdmList.value)
  drawLines(wdmList.value, wdmLayer,{lineColor:'yellow',lineWidth:3})
}, {deep: true})
//监听储存在pinia中的数据
watch(demandList, (newVal, oldVal) => {
  console.log("props.nodes",demandList.value)
  drawLines(demandList.value, demandLayer,{lineColor:'green',lineWidth:2})
}, {deep: true})
onMounted(() => {
  // 地图初始化
  initOLMap()
  drawPoints(nodeList.value, {})
  drawLines(fiberList.value, fiberLayer,{})
  drawLines(wdmList.value, wdmLayer,{lineColor:'yellow',lineWidth:3})
  drawLines(demandList.value, demandLayer,{lineColor:'green',lineWidth:2})
  // drawPoint(116.397428, 39.90923, {});
  // const pointsArr = [{
  //   longitude: 116.397428,
  //   latitude: 39.90923
  // }, {
  //   longitude: 111.924652,
  //   latitude: 34.208527
  // }, {
  //   longitude: 116.397428,
  //   latitude: 34.208527
  // },]
  // const pointsArr1 = [{
  //   longitude: 116.397428,
  //   latitude: 39.90923
  // }, {
  //   longitude: 111.924652,
  //   latitude: 36.208527
  // }, {
  //   longitude: 107.397428,
  //   latitude: 31.208527,
  // },]
  // console.log(props)
  // if (props.nodes!=null) {
  //
  //   // drawPoint(props.nodes, {})
  // }

  // drawLine(pointsArr1, {lineColor: 'blue'})
  // addTextAnnotation('测试1111', {longitude: 116.397428, latitude: 39.90923}, {color: 'blue'})
  // addTextAnnotation(props.text.text, props.text.points, props.text.style)
})


/**
 * Date:2024/3/26
 * Author:zx
 * Function:【文字标注】
 * @param 无
 */
const addTextAnnotation = (text, point,style) => {
  // 创建一个点特征（Feature）作为文本标注的位置
  let pointFeature = new Feature({
    geometry: new Point(fromLonLat([point.longitude,point.latitude])) // 设置点的坐标
  });

  // 创建一个带有文本的样式（Style）
  let textStyle = new Style({
    text: new Text({
          text: text, // 文本内容
          font: style.font??'18px Arial, sans-serif', // 字体样式
          fill: new Fill({color: style.fillColor?? 'red'}), // 文本填充颜色
          stroke: new Stroke({color: style.strokeColor??'white', width: style.strokeWidth??8}), // 文本边框样式
          offsetX: style.offsetX??0, // 文本水平偏移量
          offsetY: style.offsetY??15, // 文本垂直偏移量
          textAlign: style.textAlign??'center' // 文本水平对齐方式
        })
  });

  pointFeature.setStyle(textStyle);

  // 创建一个特征源（Source）并添加点特征
  let source = new VectorSource();
  source.addFeature(pointFeature);

  // 创建一个矢量图层（Layer）并设置特征源
  let layer = new VectorLayer({
    source: source
  });

  // 将图层添加到地图上
  map.addLayer(layer);
};

/**
 * Date:2024/3/26
 * @param nodeList
 * @param style
 */
const drawPoints = (nodeList, style) => {
  let pointFeatures = [];
  // map.removeLayer(pointLayer)
  pointLayer.getSource().clear();
  for (let i = 0; i < nodeList.length; i++) {
    let feature = new Feature({
      title: 'point',
      geometry: new Point(fromLonLat([nodeList[i].longitude, nodeList[i].latitude])) // 转换坐标
    })
    // 设置特征样式（Style）:
    feature.setStyle(
        new Style({
          // 使用 CircleStyle 创建一个圆形的点
          image: new CircleStyle({
            fill: new Fill({
              color: 'blue',
            }),
            radius: 5,
          }),
        })
    );
    feature.setId(nodeList[i].nodeName);
    pointFeatures.push(feature)
  }
  // pointSource = new VectorSource()
  // pointSource.addFeatures(pointFeatures)
  // 创建图层并设置源（Layer）
  // VectorLayer表示一个矢量图层，它由一系列矢量要素（Feature）组成，用于在地图上显示地理数据。
  // pointLayer = new VectorLayer()
  // pointLayer.setSource(pointSource)
  // map.addLayer(pointLayer)
  pointLayer.getSource().addFeatures(pointFeatures)
}


/**
 * Date:2024/3/26
 * @param nodeList
 * @param style
 */
const drawLines = (fiberList,layer, style) => {
  let lineFeatures = [];
  layer.getSource().clear()
  for (let i = 0; i < fiberList.length; i++) {
    let feature = new Feature({
      title: 'line',
      geometry: new LineString([
        fromLonLat([fiberList[i].sourceNode.longitude, fiberList[i].sourceNode.latitude]), // 起点经纬度坐标
        fromLonLat([fiberList[i].targetNode.longitude, fiberList[i].targetNode.latitude]), // 终点经纬度坐标
        // 你可以在这里添加更多的坐标点，以绘制更复杂的线
      ])
    })
    // 设置特征样式（Style）:
    feature.setStyle(
        new Style({
          stroke: new Stroke({
            color: style?.lineColor ?? 'red', // 线的颜色
            width: style?.lineWidth ?? 5, // 线的宽度
          })
        })
    );
    feature.setId(fiberList[i].name);
    lineFeatures.push(feature)
  }
  // lineSource = new VectorSource()
  // lineSource.addFeatures(lineFeatures)
  // // 创建图层并设置源（Layer）
  // // VectorLayer表示一个矢量图层，它由一系列矢量要素（Feature）组成，用于在地图上显示地理数据。
  // layer = new VectorLayer()
  // layer.setSource(lineSource)
  // map.addLayer(layer)
  layer.getSource().addFeatures(lineFeatures)
}


/**
 * Date:2024/3/26
 * @param node
 * @param style
 */
const drawPoint = (node, style) => {
  // 创建点特征（Feature）:
  let feature = new Feature({
    title: 'point',
    geometry: new Point(fromLonLat([node.longitude, node.latitude])) // 转换坐标
  })
  // 设置特征样式（Style）:
  feature.setStyle(
      new Style({
        // 使用 CircleStyle 创建一个圆形的点
        image: new CircleStyle({
          fill: new Fill({
            color: 'blue',
          }),
          radius: 5,
        }),
      })
  );
  feature.setId(node.name);

  // 创建和添加特征到源（Source）
  // VectorSource表示一个矢量要素源，它用于存储和显示地理数据。
  const pointSource = new VectorSource()
  pointSource.addFeature(feature)
  // 创建图层并设置源（Layer）
  // VectorLayer表示一个矢量图层，它由一系列矢量要素（Feature）组成，用于在地图上显示地理数据。
  if (pointLayer==null) {
    pointLayer = new VectorLayer()
  }
  pointLayer.setSource(pointSource)
  map.addLayer(pointLayer)
}

const drawLine = (pointsArr, style) => {

  // console.log("pointsArr")
  // console.log(pointsArr)

  const fromLonLatArr = pointsArr.map((p) => {
    return fromLonLat([p.longitude, p.latitude])
  })
  console.log(fromLonLatArr)
  // 创建线特征（Feature）:
  let lineFeature = new Feature({

    geometry: new LineString(fromLonLatArr)
  });

  // 设置线特征的样式（Style）:
  lineFeature.setStyle(
      new Style({
        stroke: new Stroke({
          color: style?.lineColor ?? 'blue', // 线的颜色
          width: style?.lineWidth ?? 5, // 线的宽度
        })
      })
  );

  // 创建和添加特征到源（Source）
  let LineSource = new VectorSource();
  LineSource.addFeature(lineFeature);

  // 创建图层并设置源（Layer）
  let lineLayer = new VectorLayer();
  lineLayer.setSource(LineSource);

  // 将图层添加到地图上
  map.addLayer(lineLayer);

}

/**
 * 地图初始化
 */
function initOLMap() {
  // 创造地图实例
  map = new Map({
    // 设置地图容器的ID
    target: 'olMap',
    // 定义地图的图层列表，用于显示特定的地理信息。
    layers: [
      // 高德地图
      // TileLayer表示一个瓦片图层，它由一系列瓦片（通常是图片）组成，用于在地图上显示地理数据。
      new TileLayer({
        // 设置图层的数据源为XYZ类型。XYZ是一个通用的瓦片图层源，它允许你通过URL模板来获取瓦片
        source: new XYZ({
          url: props.url,
        })
      }),
        fiberLayer,
        wdmLayer,
        demandLayer,
        pointLayer,
    ],
    // 设置地图的视图参数
    // View表示地图的视图，它定义了地图的中心点、缩放级别、旋转角度等参数。
    view: new View(props.viewConfig),
    // 按住shift进行旋转
    interactions: defaultInteractions().extend([new DragRotateAndZoom()]),
    // 控件
    controls: defaults().extend([
      new FullScreen({
        className: 'myStyle2',
      }), // 全屏
      // new MousePosition(), // 显示鼠标当前位置的地图坐标
      new ScaleLine({
        className: 'myStyle',
      }),// 显示比例尺
    ])

  })

  // 事件
  map.on('moveEnd', (e: any) => {
    console.log('地图移动', e)
    // 获取当前缩放级别
    var zoomLevel = map.getView().getZoom();
    console.log('当前缩放级别：', zoomLevel);
  })
  map.on('click', (e: any) => {
    // console.log('地图点击', e)
    var coordinate = e.coordinate;

    // 将投影坐标转换为经纬度坐标
    var lonLatCoordinate = toLonLat(coordinate);
    // 输出转换后的经纬度坐标
    // console.log('经纬度坐标：', lonLatCoordinate);
    // console.log(props.eventConfig)
    props.eventConfig.clickEvent(lonLatCoordinate)
  })

}
</script>
<style>
.myStyle {
  color: #535bf2;
  position: absolute;
  bottom: 0;
  left: 0;
}

.ol-map .ol-zoom {
  position: absolute;
  color: red;
  top: 10px;
  left: 10px;
}

#olMap {
  width: 100%;
  height: 100%;
}

/*.ol-map .ol-zoom button {*/
/*  background-color: red;*/

/*}*/

.ol-map .ol-rotate button {
  display: none;
}

.myStyle2 {
  position: absolute;
  top: 0;
  right: 0;
}

</style>